﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Leap;

namespace EikonLeap
{
    public class HandMoveEventArgs
    {
        internal Hand hand;

        public Hand Hand
        {
            get
            {
                return hand;
            }
        }
    }

    public class GraspEventArgs
    {
        internal Hand hand;

        public Hand Hand
        {
            get
            {
                return hand;
            }
        }
    }

    public class ReleaseEventArgs
    {
        internal Hand hand;

        public Hand Hand
        {
            get
            {
                return hand;
            }
        }
    }

    public class SwipeEventArgs
    {
        internal SwipeGesture gesture;

        public SwipeGesture Gesture
        {
            get
            {
                return gesture;
            }
        }
    }

    public class CircleEventArgs
    {
        internal CircleGesture gesture;
        internal float handrotateprob;

        public CircleGesture Gesture
        {
            get
            {
                return gesture;
            }
        }

        public float Probability
        {
            get
            {
                return handrotateprob;
            }
        }
    }

    public class ScreenTapEventArgs
    {
        internal ScreenTapGesture gesture;

        public ScreenTapGesture Gesture
        {
            get
            {
                return gesture;
            }
        }
    }

    public class KeyTapEventArgs
    {
        internal KeyTapGesture gesture;

        public KeyTapGesture Gesture
        {
            get
            {
                return gesture;
            }
        }
    }

    public class LeapDimension : Listener
    {
        public delegate void DimensionEventHandler();

        public delegate void SwipeEventHandler(SwipeEventArgs arg);
        public delegate void CircleEventHandler(CircleEventArgs arg);
        public delegate void HandMoveEventHandler(HandMoveEventArgs arg);
        public delegate void GraspEventHandler(GraspEventArgs arg);
        public delegate void ReleaseEventHandler(ReleaseEventArgs arg);
        public delegate void ScreenTapEventHandler(ScreenTapEventArgs arg);
        public delegate void KeyTapEventHandler(KeyTapEventArgs arg);

        public event DimensionEventHandler Init;
        public event DimensionEventHandler Exit;
        public event DimensionEventHandler Connect;
        public event DimensionEventHandler Disconnect;
        public event DimensionEventHandler FocusGained;
        public event DimensionEventHandler FocusLost;
        public event SwipeEventHandler SwipeBegin;
        public event SwipeEventHandler SwipeUpdate;
        public event SwipeEventHandler SwipeEnd;
        public event HandMoveEventHandler HandMove;
        public event GraspEventHandler Grasp;
        public event ReleaseEventHandler Release;
        public event CircleEventHandler CircleBegin;
        public event CircleEventHandler CircleUpdate;
        public event CircleEventHandler CircleEnd;
        public event ScreenTapEventHandler ScreenTap;
        public event KeyTapEventHandler KeyTap;

        public const int HistoryFrameOfSwipe = 10;
        public const int HistoryFrameOfCircle = 10;
        public const int HistoryFrameOfGraspRelease = 10;
        public const int HistoryFrameOfScreenTap = 10;
        public const int HistoryFrameOfKeyTap = 10;

        private Controller controller;
        private bool accepthandgrasp;
        private bool accepthandrelease;
        private int fingeronhand;

        public LeapDimension()
        {
            controller = new Controller();
            accepthandgrasp = true;
            accepthandrelease = true;
            fingeronhand = 0;
        }

        public void Initialize()
        {
            controller.AddListener(this);
        }

        public void Terminate()
        {
            controller.RemoveListener(this);
            controller.Dispose();
        }

        public override void OnInit(Controller controller)
        {
            if (Init != null)
            {
                Init();
            }
        }

        public override void OnExit(Controller controller)
        {
            if (Exit != null)
            {
                Exit();
            }
        }

        public override void OnConnect(Controller controller)
        {
            controller.EnableGesture(Gesture.GestureType.TYPECIRCLE);
            controller.EnableGesture(Gesture.GestureType.TYPESWIPE);
            controller.EnableGesture(Gesture.GestureType.TYPESCREENTAP);
            controller.EnableGesture(Gesture.GestureType.TYPEKEYTAP);

            if (Connect != null)
            {
                Connect();
            }
        }

        public override void OnDisconnect(Controller controller)
        {
            if (Disconnect != null)
            {
                Disconnect();
            }
        }

        public override void OnFocusGained(Controller controller)
        {
            if (FocusGained != null)
            {
                FocusGained();
            }
        }

        public override void OnFocusLost(Controller controller)
        {
            if (FocusLost != null)
            {
                FocusLost();
            }
        }

        public override void OnFrame(Controller controller)
        {
            Frame frame = controller.Frame();

            Frame prevframe = null;
            prevframe = controller.Frame(HistoryFrameOfGraspRelease);

            HandlingHandMove(controller, prevframe);
            if (HandlingGraspRelease(controller, prevframe))
                return;

            GestureList gestures = frame.Gestures();
            Gesture gesture = gestures[0];
            if (!gesture.IsValid)
                return;

            switch (gesture.Type)
            {
                case Gesture.GestureType.TYPESCREENTAP:
                    prevframe = controller.Frame(HistoryFrameOfScreenTap);
                    HandlingScreenTapGesture(gesture, prevframe);
                    break;
                case Gesture.GestureType.TYPEKEYTAP:
                    prevframe = controller.Frame(HistoryFrameOfKeyTap);
                    HandlingKeyTapGesture(gesture, prevframe);
                    break;
                case Gesture.GestureType.TYPECIRCLE:
                    prevframe = controller.Frame(HistoryFrameOfCircle);
                    HandlingCircleGesture(gesture, prevframe);
                    break;
                case Gesture.GestureType.TYPESWIPE:
                    prevframe = controller.Frame(HistoryFrameOfSwipe);
                    HandlingSwipeGesture(gesture, prevframe);
                    break;
                default:
                    break;
            }
        }

        private bool HandlingHandMove(Controller controller, Frame prevframe)
        {
            Frame frame = controller.Frame();
            if (frame.Hands.Empty)
                return false;

            Hand hand = frame.Hands[0];
            if (!hand.IsValid || hand.Fingers.Empty)
                return false;
            
            if (HandMove != null)
            {
                HandMoveEventArgs arg = new HandMoveEventArgs();
                arg.hand = hand;

                HandMove(arg);
            }

            return true;
        }

        private bool HandlingGraspRelease(Controller controller, Frame prevframe)
        {
            Frame frame = controller.Frame();
            if (frame.Hands.Empty)
                return false;

            Hand hand = frame.Hands[0];
            if (!hand.IsValid || hand.Fingers.Empty)
                return false;

            fingeronhand = hand.Fingers.Count;

            if (prevframe.Hands.Empty)
                return false;

            Hand prevhand = prevframe.Hands[0];
            if (!prevhand.IsValid || prevhand.Fingers.Empty)
                return false;

            if ((prevhand.Fingers.Count - fingeronhand) > 2)
            {
                if (accepthandgrasp && Grasp != null)
                {
                    GraspEventArgs arg = new GraspEventArgs();
                    arg.hand = hand;

                    Grasp(arg);
                    accepthandgrasp = false;
                }
            }
            else if ((fingeronhand - prevhand.Fingers.Count) > 2)
            {
                if (accepthandrelease && Release != null)
                {
                    ReleaseEventArgs arg = new ReleaseEventArgs();
                    arg.hand = hand;

                    Release(arg);
                    accepthandrelease = false;
                }
            }
            else
            {
                accepthandgrasp = true;
                accepthandrelease = true;
                return false;
            }

            return true;
        }

        private bool HandlingSwipeGesture(Gesture gesture, Frame prevframe)
        {
            if (!gesture.IsValid || gesture.State == Gesture.GestureState.STATEINVALID)
                return false;

            SwipeGesture swipe = new SwipeGesture(gesture);
            SwipeEventArgs arg = new SwipeEventArgs();
            arg.gesture = swipe;

            if (gesture.State == Gesture.GestureState.STATESTART)
            {
                if (SwipeBegin != null)
                {
                    SwipeBegin(arg);
                    return true;
                }
            }
            else if (gesture.State == Gesture.GestureState.STATEUPDATE)
            {
                if (SwipeUpdate != null)
                {
                    SwipeUpdate(arg);
                    return true;
                }
            }
            else if (gesture.State == Gesture.GestureState.STATESTOP)
            {
                if (SwipeEnd != null)
                {
                    SwipeEnd(arg);
                    return true;
                }
            }

            return false;
        }

        private bool HandlingCircleGesture(Gesture gesture, Frame prevframe)
        {
            if (!gesture.IsValid || gesture.State == Gesture.GestureState.STATEINVALID)
                return false;

            CircleGesture circle = new CircleGesture(gesture);
            CircleEventArgs arg = new CircleEventArgs();
            arg.gesture = circle;

            if (gesture.State == Gesture.GestureState.STATESTART)
            {
                if (CircleBegin != null)
                {
                    CircleBegin(arg);
                    return true;
                }
            }
            else if (gesture.State == Gesture.GestureState.STATEUPDATE)
            {
                if (CircleUpdate != null)
                {
                    CircleUpdate(arg);
                    return true;
                }
            }
            else if (gesture.State == Gesture.GestureState.STATESTOP)
            {
                if (CircleEnd != null)
                {
                    CircleEnd(arg);
                    return true;
                }
            }

            return false;
        }

        private bool HandlingScreenTapGesture(Gesture gesture, Frame prevframe)
        {
            if (!gesture.IsValid || gesture.State == Gesture.GestureState.STATEINVALID)
                return false;

            ScreenTapGesture screentap = new ScreenTapGesture(gesture);
            if (ScreenTap != null)
            {
                ScreenTapEventArgs arg = new ScreenTapEventArgs();
                arg.gesture = screentap;

                ScreenTap(arg);
                return true;
            }

            return false;
        }

        private bool HandlingKeyTapGesture(Gesture gesture, Frame prevframe)
        {
            if (!gesture.IsValid || gesture.State == Gesture.GestureState.STATEINVALID)
                return false;

            KeyTapGesture keytap = new KeyTapGesture(gesture);
            if (KeyTap != null)
            {
                KeyTapEventArgs arg = new KeyTapEventArgs();
                arg.gesture = keytap;

                KeyTap(arg);
                return true;
            }

            return false;
        }
    }
}
